package com.zhao.dota.controller;

import cn.hutool.core.date.SystemClock;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.zhao.dota.bo.AuthenticateUser;
import com.zhao.dota.security.SecurityUtil;
import com.zhao.dota.security.store.TokenStore;
import com.zhao.dota.security.token.AccessToken;
import com.zhao.dota.security.token.InternalAccessToken;
import com.zhao.dota.service.UserService;
import com.zhao.dota.service.WechatService;
import com.zhao.dota.struct.Result;
import com.zhao.dota.struct.WsMessage;
import lombok.extern.slf4j.Slf4j;
import org.expressme.openid.Association;
import org.expressme.openid.Endpoint;
import org.expressme.openid.OpenIdManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Objects;

@RestController
@RequestMapping("/login")
@Slf4j
public class LoginController {

    @Resource
    private TokenStore tokenStore;
    @Resource
    private UserService userService;
    @Resource
    private DefaultKaptcha defaultKaptcha;
    @Resource
    private WechatService wechatService;
    @Resource
    private WebSocketServer webSocketServer;
    @Value("${server.domain}")
    private String steamLoginRedirectDomain;

    @GetMapping(value = "/captcha", produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public byte[] captcha(HttpSession session) {
        String text = defaultKaptcha.createText();
        BufferedImage image = defaultKaptcha.createImage(text);
        byte[] bytes = null;
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()){
            ImageIO.write(image, "jpg", out);
            bytes = out.toByteArray();
            session.setAttribute("captcha", text);
        } catch (IOException e) {
            log.error("生成验证码失败", e);
        }
        return bytes;
    }

    @GetMapping(value = "/wechatLogin", produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public byte[] wechatLogin(String id) {
        byte[] bytes = wechatService.loginWxacode(id);
        return bytes;
    }

    @PostMapping("/captcha")
    public Result<Void> verifyCaptcha(String captcha, HttpSession session) {
        if (Objects.equals(captcha, session.getAttribute("captcha"))) {
            return Result.success();
        }
        return Result.error();
    }

    @GetMapping("/refreshAccessToken")
    public Result<AccessToken> refreshAccessToken(String refreshToken) {
        AuthenticateUser authenticateUser = tokenStore.readAuthenticationForRefreshToken(refreshToken);
        AccessToken accessToken = tokenStore.getAccessToken(refreshToken);
        if (authenticateUser == null || accessToken == null) {
            return Result.error("refresh token失效");
        }
        int timeout = accessToken.getTimeout();
        InternalAccessToken internalAccessToken = new InternalAccessToken((int) (SystemClock.now() / 1000) + timeout);
        internalAccessToken.setRefreshToken(refreshToken);
        tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);
        tokenStore.storeAccessToken(internalAccessToken, authenticateUser);
        return Result.success(internalAccessToken);
    }

    @GetMapping("/scanWxacode")
    public Result<Void> scanWxacode(String id) {
        WsMessage<?> wsMessage = new WsMessage<>();
        wsMessage.setAction("scan");
        webSocketServer.sendMessage(id, wsMessage);
        return Result.success();
    }

    @PostMapping("/loginPc")
    public Result<Void> loginPc(String id, String code) {
        WsMessage<String> wsMessage = new WsMessage<>();
        wsMessage.setAction("login");
        wsMessage.setData(code);
        webSocketServer.sendMessage(id, wsMessage);
        return Result.success();
    }

    @GetMapping("/getSteamLoginUrl")
    public Result<String> getSteamLoginUrl(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        StringBuffer requestURL = request.getRequestURL();
        String domain = requestURL.toString().replace(requestURI, "");

        String code = userService.steamLoginCode(SecurityUtil.getAuthenticateUser());
        OpenIdManager openIdManager = new OpenIdManager();
        openIdManager.setRealm(domain);
        openIdManager.setReturnTo(domain + "/login/" + code + "/steamLogin");
        Endpoint steam = new Endpoint(STEAM_LOGIN, "steam", 60 * 1000);
        Association association = new Association();
        String authenticationUrl = openIdManager.getAuthenticationUrl(steam, association);
        return Result.success(authenticationUrl);
    }

    @GetMapping("/{code}/steamLogin")
    public Result<Void> steamLogin(@RequestParam(value = "openid.claimed_id", required = false) String claimedId, @PathVariable String code) {
        if (claimedId == null) {
            return Result.error();
        }
        String steamId = claimedId.substring(claimedId.indexOf(OPEN_ID_PREFIX) + OPEN_ID_PREFIX.length());
        boolean b = userService.bindSteam(code, Long.valueOf(steamId));
        return Result.complete(b);
    }

    private static final String STEAM_LOGIN = "https://steamcommunity.com/openid/login";

    private static final String OPEN_ID_PREFIX = "openid/id/";

}
